#include "network.h"


//  ​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​
//  * 初始化函数 - 建立连接并设置初始状态 - 用于登录成功后的文件目录操作
//  * 关键操作：
//  * 1. 非阻塞connect
//  * 2. 超时设置
//  * 3. 初始状态配置
//  ​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​*​**​
int init_client_noblock(ClientContext *ctx, const char *ip, int port) 
{
    // 创建套接字（先创建阻塞的）
    ctx->sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (ctx->sockfd < 0) {
        perror("socket");
        return -1;
    }

    // 设置为非阻塞模式
    int flags = fcntl(ctx->sockfd, F_GETFL, 0);
    if (fcntl(ctx->sockfd, F_SETFL, flags | O_NONBLOCK) < 0) {
        perror("fcntl");
        close(ctx->sockfd);
        return -1;
    }

    // 配置服务器地址
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr(ip);

    // 发起非阻塞连接
    int ret = connect(ctx->sockfd, (struct sockaddr *)&addr, sizeof(addr));
    if (ret == 0) {
        // 连接立即成功（理论上非阻塞连接几乎不会立即成功）
        goto connected;
    }

    // 检查连接是否在进行中
    fd_set wfds;
    FD_ZERO(&wfds);
    FD_SET(ctx->sockfd, &wfds);

    struct timeval tv;
    tv.tv_sec = 5;  // 5秒超时
    tv.tv_usec = 0;

    ret = select(ctx->sockfd + 1, NULL, &wfds, NULL, &tv);
    if (ret <= 0) {
        // 超时或错误
        fprintf(stderr, "connect timeout or error\n");
        close(ctx->sockfd);
        return -1;
    }

    // 检查连接是否真的成功
    int error = 0;
    socklen_t len = sizeof(error);
    if (getsockopt(ctx->sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0 || error != 0) {
        fprintf(stderr, "connect failed\n");
        close(ctx->sockfd);
        return -1;
    }

connected:
    // 连接成功后的初始化
    ctx->state = STATE_IDLE;
    strcpy(ctx->current_dir, "/");
    return 0;
}




/* 发送协议命令（自动添加协议头）
 * 参数：
 *   ctx        - 客户端上下文
 *   cmd        - 命令类型(来自protocol.h)
 *   data       - 附加数据(如命令参数)
 *   data_len   - 数据长度
 * 工作流程：
 *   1. 填充协议头结构
 *   2. 发送协议头
 *   3. 发送附加数据(如果有) */
int send_command(ClientContext *ctx, CommandType_e cmd, const char *data, size_t data_len) {
    protocol_header_t header = {
        .magic = MAGIC_NUMBER,
        .command = cmd,
        .data_length = data_len,
        .resp_type = SUCESS
    };

    // Token处理（保持原逻辑）
    if (ctx->state == STATE_IDLE || ctx->state == STATE_AWAIT_RESP) {
        strncpy(header.token, ctx->token, sizeof(header.token));
    } else {
        memset(header.token, 0, sizeof(header.token));
    }

    // 非阻塞发送头（核心改造点）
    size_t header_sent = 0;
    while (header_sent < HEADER_LENGTH) {
        int ret = send(ctx->sockfd, 
                      (char*)&header + header_sent, 
                      HEADER_LENGTH - header_sent, 
                      0);
        
        if (ret < 0) {
            // 非阻塞情况下正常重试
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                continue; // 等待下次可写事件
            }
            fprintf(stderr, "[ERROR] Header send failed\n");
            return -1;
        }
        header_sent += ret;
    }

    // 非阻塞发送负载（核心改造点）
    if (data_len > 0 && data != NULL) {
        size_t data_sent = 0;
        while (data_sent < data_len) {
            int ret = send(ctx->sockfd, 
                          data + data_sent, 
                          data_len - data_sent, 
                          0);
            
            if (ret < 0) {
                // 非阻塞情况下正常重试
                if (errno == EAGAIN || errno == EWOULDBLOCK) {
                    continue; // 等待下次可写事件
                }
                fprintf(stderr, "[ERROR] Payload send failed\n");
                return -2;
            }
            data_sent += ret;
        }
    }
    
    return 0;
}


/* 接收协议响应（自动解析协议头）
 * 安全措施：
 * 1. 缓冲区溢出检查
 * 2. 魔数验证
 * 3. 数据长度验证 */
int receive_response(ClientContext *ctx, protocol_header_t *header,
                     char *buf, size_t buf_size) 
{
    // 非阻塞接收头（核心改造点）
    size_t header_received = 0;
    while (header_received < HEADER_LENGTH) {
        int ret = recv(ctx->sockfd, 
                      (char*)header + header_received, 
                      HEADER_LENGTH - header_received, 
                      0);
        
        if (ret < 0) {
            // 非阻塞情况下正常重试
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                continue; // 等待下次可读事件
            }
            fprintf(stderr, "[ERROR] Header receive failed\n");
            return -1;
        }
        
        // 连接关闭检测
        if (ret == 0) {
            fprintf(stderr, "[ERROR] Connection closed\n");
            return -5;
        }
        
        header_received += ret;
    }

    // 魔数验证（保持原逻辑）
    if (header->magic != MAGIC_NUMBER) {
        fprintf(stderr, "[ERROR] Invalid magic number: %X\n", header->magic);
        return -2;
    }

    // 非阻塞接收负载（核心改造点）
    if (header->data_length > 0) {
        // 缓冲区检查（保持原逻辑）
        if (header->data_length > buf_size) {
            fprintf(stderr, "[ERROR] Buffer too small (%zu < %d)\n",
                    buf_size, header->data_length);
            return -3;
        }
        
        size_t payload_received = 0;
        while (payload_received < header->data_length) {
            int ret = recv(ctx->sockfd, 
                          buf + payload_received, 
                          header->data_length - payload_received, 
                          0);
            
            if (ret < 0) {
                // 非阻塞情况下正常重试
                if (errno == EAGAIN || errno == EWOULDBLOCK) {
                    continue; // 等待下次可读事件
                }
                fprintf(stderr, "[ERROR] Payload receive failed\n");
                return -4;
            }
            
            // 连接关闭检测
            if (ret == 0) {
                fprintf(stderr, "[ERROR] Connection closed during payload\n");
                return -5;
            }
            
            payload_received += ret;
        }
    }
    
    return 0;
}
